#include <stdio.h>
#include "dsl_button.h"
#include "driver/gpio.h"
#include "esp_log.h"

static uint8_t button_size = 0;
uint8_t button_flag[DSL_BUTTON_SIZE];
dsl_button_t button_list[];
// 0000 0000
// 0 REPEAT LONGPRESS DBLICK CLICK PRESSUP PRESSDOWN HOLD

#define DSL_BUTTON_TIME_DBCLICK 200
#define DSL_BUTTON_TIME_LONGPRESS 2000
#define DSL_BUTTON_TIME_REPEAT 100

gpio_num_t gpio_list[DSL_BUTTON_SIZE] = {GPIO_NUM_19, GPIO_NUM_18, GPIO_NUM_17, GPIO_NUM_16, GPIO_NUM_15};

void dsl_button_init(void)
{    
    gpio_set_direction(GPIO_NUM_19, GPIO_MODE_INPUT);
    gpio_set_direction(GPIO_NUM_18, GPIO_MODE_INPUT);
    gpio_set_direction(GPIO_NUM_17, GPIO_MODE_INPUT);
    gpio_set_direction(GPIO_NUM_16, GPIO_MODE_INPUT);
    gpio_set_direction(GPIO_NUM_15, GPIO_MODE_INPUT);

    gpio_set_pull_mode(GPIO_NUM_19, GPIO_PULLUP_ONLY);
    gpio_set_pull_mode(GPIO_NUM_18, GPIO_PULLUP_ONLY);
    gpio_set_pull_mode(GPIO_NUM_17, GPIO_PULLUP_ONLY);
    gpio_set_pull_mode(GPIO_NUM_16, GPIO_PULLUP_ONLY);
    gpio_set_pull_mode(GPIO_NUM_15, GPIO_PULLUP_ONLY);
}

dsl_button_status_t dsl_button_get_status(uint8_t index)
{
    if (gpio_get_level(gpio_list[index]) == 0)
    {
        return DSL_BUTTON_STATUS_PRESS;
    }

    return DSL_BUTTON_STATUS_UNPRESS;
}

uint8_t dsl_button_check(button_type_t button_type, uint8_t flag)
{
    if (button_flag[button_type] & flag)
    {
        if (flag != DSL_BUTTON_EVENT_HOLD)
        {
            button_flag[button_type] &= ~flag;
        }

        return 1;
    }

    return 0;
}

void dsl_button_tick(void)
{
    static uint8_t count = 0;
    static dsl_button_status_t current_state[DSL_BUTTON_SIZE] = {0}, last_state[DSL_BUTTON_SIZE] = {0};
    static uint8_t state[DSL_BUTTON_SIZE] = {0};
    static uint8_t time[DSL_BUTTON_SIZE] = {0};

    count++;

    for (uint8_t i = 0; i < DSL_BUTTON_SIZE; i++)
    {
        // 每ms减1
        if (time[i] > 0)
        {
            time[i]--;
        }
    }

    if (count < 20)
    {
        return;
    }

    count = 0;

    for (int i = 0; i < DSL_BUTTON_SIZE; i++)
    {
        current_state[i] = dsl_button_get_status(i);
        if (current_state[i] == DSL_BUTTON_STATUS_PRESS)
        {
            button_flag[i] |= DSL_BUTTON_EVENT_HOLD; // HOLD = 1 按键保持按下
        }
        else
        {
            button_flag[i] &= ~DSL_BUTTON_EVENT_HOLD; // HOLD = 0 按键保持抬起
        }

        if (current_state[i] == DSL_BUTTON_STATUS_PRESS && last_state[DSL_BUTTON_SIZE] == DSL_BUTTON_STATUS_PRESS)
        {
            // PRESSDOWN = 1 按键按下
            button_flag[i] |= DSL_BUTTON_EVENT_PRESSDOWN;
        }

        if (current_state[i] == DSL_BUTTON_STATUS_UNPRESS && last_state[DSL_BUTTON_SIZE] == DSL_BUTTON_STATUS_PRESS)
        {
            // PRESSUP = 1 按键抬起
            button_flag[i] |= DSL_BUTTON_EVENT_PRESSUP;
        }

        switch (state[i])
        {
        case 0: // 空闲时间，检测按键按下，如果按键按下，进入状态1，并设置长按时间
            if (current_state[i] == DSL_BUTTON_STATUS_PRESS)
            {
                time[i] = DSL_BUTTON_TIME_LONGPRESS;
                state[i] = 1;
            }

            break;
        case 1: // 检测按键抬起，如果抬起，进入状态2，并设置双击时间，否则检测长按时间，如果长按时间到，进入状态4
            if (current_state[i] == DSL_BUTTON_STATUS_UNPRESS)
            {
                time[i] = DSL_BUTTON_TIME_DBCLICK;
                state[i] = 2;
            }
            else if (time[i] == 0)
            { // 长按时间到
                // 设置重复时间
                time[i] = DSL_BUTTON_TIME_REPEAT;
                // 设置长按标志 LONGPRESS = 1
                button_flag[i] |= DSL_BUTTON_EVENT_LONGPRESS;
                // 设置状态
                state[i] = 4;
            }
            break;
        case 2:
            if (current_state[i] == DSL_BUTTON_STATUS_PRESS)
            {
                // 设置双击标志 DBLICK = 1
                button_flag[i] |= DSL_BUTTON_EVENT_DBCLICK;
                state[i] = 3;
            }
            else if (time[i] == 0) // 双击时间到
            {
                // 设置单击标志 CLICK = 1
                button_flag[i] |= DSL_BUTTON_EVENT_CLICK;
                state[i] = 0;
            }

            break;
        case 3:
            if (current_state[i] == DSL_BUTTON_STATUS_UNPRESS)
            {
                state[i] = 0;
            }
            break;
        case 4:
            if (current_state[i] == DSL_BUTTON_STATUS_UNPRESS)
            {
                state[i] = 0;
            }
            else if (time[i] == 0)
            {
                time[i] = DSL_BUTTON_TIME_DBCLICK;
                // 设置重复标志 REPEAT = 1
                button_flag[i] |= DSL_BUTTON_EVENT_REPEAT;
                // 设置状态
                state[i] = 4;
            }
            break;
        default:
            break;
        }
    }
}